<?php
/**
 * Created by PhpStorm.
 * User: shutao
 */

namespace wechat\controllers;

use tt\common\help\HookHelp;
use tt\common\help\LogHelp;
use tt\common\help\ModelHelper;
use tt\common\help\RequestHelp;
use tt\common\help\ResponseHelp;
use ttcommon\aop\annotation\ControllerAnnotation;
use ttcommon\base\Data;
use ttext\backend\admin\models\User;
use ttext\backend\admin\services\UserService;
use wechat\hook\AuthHook;
use wechat\models\WeSessionKey;
use wechat\models\WeUser;
use wechat\models\WeUserOpenid;
use wechat\services\WeConfigService;
use wechat\services\WeiXinService;


/**
 * @title [小程序]平台连接
 * @access public
 */
class XcxController extends BaseWechatController implements ControllerAnnotation
{
    public $enableCsrfValidation = false;


// 小程序登录流程
// https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
    public function actionCode()
    {

        $data = RequestHelp::requestData();
        try {
            Data::hasSet($data, 'code');
        } catch (\Exception $e) {
            ResponseHelp::returnNo($e->getMessage());
        }
        $weConfig = [];
        if ($appid = Data::hasValue($data, 'appid')) {
            $weConfig = WeiXinService::weConfigFromAppid($appid);
        }
        $app = WeiXinService::xcxApp($weConfig);

        $session = $app->auth->session($data['code']);
        if (isset($session['errocde']) && !$session['errocde']) {
            ResponseHelp::returnNo('code2session失败:' . $session['errMsg']);
        }

//        $session = ['session_key' => 'dMK8qGMRMOVhCP6x9OjKEw==', 'openid' => 1];

//        登录 code2Session
        // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
        /*
         * openid string 用户唯一标识
         * session_key string 会话密钥
         * unionid string 开放平台的唯一标识符(可能不下发）
         * errcode number 错误码
         * errMsg string 错误信息
         */
//ResponseHelp::send($session);
        if (!isset($session['openid'])) {
            ResponseHelp::returnNo('openid not get from wechat server.');
        }
        // 检查此用户是否注册过
        $uid = 0;
        $wuid = 0;
        // 1. openid 是否登记过
        if ($userOpenid = WeUserOpenid::find()->select(['we_id'])
            ->where(['user_openid' => $session['openid']])->one()) {
            $wuid = $userOpenid['we_id']; // ------------- we_user.id
            $weUser = WeUser::find()->where(['id' => $userOpenid['we_id']])->select(['weixin_unionid', 'uid'])->asArray()->one();
            $uid = $weUser['uid'];
            // 1.1 是否需要修改 unionid
            if ($unionid = Data::hasValue($session, 'unionid')) {
                if ($weUser['weixin_unionid'] != $unionid) {
                    $transaction = \Yii::$app->db->beginTransaction();
                    try {
                        \Yii::$app->db->createCommand()->update(
                            WeUser::tableName(),
                            ['weixin_unionid' => $unionid],
                            ['id' => $userOpenid['we_id']]
                        )->execute();

                        if (AuthHook::$createUserWhenFirstSubscribe && $weUser['uid']) {
                            \Yii::$app->db->createCommand()->update(
                                User::tableName(), ['userid' => $unionid], ['id' => $weUser['uid']]
                            )->execute();
                        }
                        $transaction->commit();
                    } catch (\Exception $e) {
                        $transaction->rollBack();
                        LogHelp::message($e->getMessage(), 'xcxCodeUpdate');
                        ResponseHelp::returnNo('注册失败');
                    }
                }
            }
        } else {
            // 2. 没有 openid
            $weUserOpenid = new WeUserOpenid();
            $weUserOpenid->we_id = 0;
            $weUserOpenid->openid = $weConfig['appid'];
            $weUserOpenid->user_openid = $session['openid'];
            $weUserOpenid->type = WeConfigService::typeFromAppid($weConfig['appid']);
            if ($weUserOpenid->insert() === false) {
                throw new \Exception(ModelHelper::errorMessages($weUserOpenid));
            }
            // 2.1 unionid 是否登记过
            // 如果没有，也不能马上注册用户，因为可能是由于多个来源导致的
            if ($unionid = Data::hasValue($session, 'unionid')) {
                if ($weUser = WeUser::find()->where(['id', 'uid'])->where(['weixin_unionid' => $unionid])->asArray()->one()) {
                    $weUserOpenid->we_id = $weUser['id'];
                    $weUserOpenid->save();
                    $uid = $weUser['uid'];
                    $wuid = $weUser['id'];
                }
            }
            // 2.2 没有登记过，则需要注册用户
            if ($weUserOpenid->we_id < 1) {
                // 快速注册用户
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    // 注册用户
                    $unionid = Data::hasValue($session, 'unionid', $session['openid']);
//                -------- 不主动创建账号，uid=0 表示还没有关联到账号
                    if (AuthHook::$createUserWhenFirstSubscribe) {
                        $user = UserService::registerWithUuid($unionid);
                        $uid = $user->id;
                    }
//                ---------
                    // 注册微信账号
                    $weUser = new WeUser();
                    $weUser->uid = $uid;
                    $weUser->weixin_unionid = $unionid;
                    if ($weUser->insert() === false) {
                        throw new \Exception(ModelHelper::errorMessages($weUser));
                    }
                    $wuid = $weUser->id; // -------------- we_user.id
                    $weUserOpenid->we_id = $wuid;
                    $weUserOpenid->save();
                    $transaction->commit();
                } catch (\Exception $e) {
                    LogHelp::message($e->getMessage(), 'xcxCodeInsert');
                    $transaction->rollBack();
                }
            }
        }

        if (!$sKey = WeSessionKey::find()->where(['session_key' => $session['session_key']])->one()) {

            // 保存 session_key 用户标记
            $sKey = new WeSessionKey();
            $sKey->attributes = [
                'code' => $data['code'],
                'openid' => $session['openid'], // 用户唯一标识 openid
                'session_key' => $session['session_key'],
                'uid' => $uid,
                'wuid' => $wuid
            ];
            if ($sKey->save() === false) {
                ResponseHelp::returnNo('保存 session key 失败');
            }

        }

        ResponseHelp::send(implode('.', [$sKey->id, $sKey->session_key]));
    }

    // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserInfo.html
    // 客户端才能获取 iv 和 encryptedData 数据
    public function actionUserinfo()
    {
        $data = RequestHelp::requestData();
        try {
            Data::hasSet($data, ['iv', 'encryptedData', 'session_key']);
            $weConfig = [];
            if ($appid = Data::hasValue($data, 'appid')) {
                $weConfig = WeiXinService::weConfigFromAppid($appid);
            }
            $app = WeiXinService::xcxApp($weConfig);
            list($id, $session_key) = explode('.', $data['session_key']);

            /** @var WeSessionKey $sKey */
            if (!$sKey = WeSessionKey::find()->where(['id' => $id])->one()) {
                ResponseHelp::returnNo('session token 不存在');
            }
            if ($sKey->session_key != $session_key) {
                ResponseHelp::returnNo('session token 错误');
            }
            // 微信返回的信息信息
            $decryptedData = $app->encryptor->decryptData($session_key, $data['iv'], $data['encryptedData']);
            /*
       Array
       (
           [openId] => oxu...Pc4
           [nickName] => 我的昵称
           [gender] => 1
           [language] => zh_CN
           [city] => Shenzhen
           [province] => Guangdong
           [country] => China
           [avatarUrl] => https://wx.qlogo.cn/mmopen/vi_32/.../132
           [unionId] => oN1iv518...Og
           [watermark] => Array
               (
                   [timestamp] => 1542167837
                   [appid] => wx77ffc9f04ec56233
               )

       )
        */
            Data::hasSet($decryptedData, ['openId', 'unionId']);

//print_r($decryptedData);exit;
            // 更新账号信息
            if (!$userOpenid = WeUserOpenid::find()->select(['we_id'])
                ->where(['user_openid' => $decryptedData['openId']])->one()) {
                ResponseHelp::returnNo('user openid not found');
            }

            /** @var WeUser $weUser */
            $weUser = WeUser::find()->where(['id' => $userOpenid['we_id']])->one();

            $sKey->uid = $weUser->uid;
            $sKey->wuid = $weUser->id;
            if ($sKey->save() === false) {
                ResponseHelp::returnNo('更新 session token 信息错误');
            }
            if ($weUser->weixin_unionid != $decryptedData['unionId']) {
                $weUser->nickname = Data::hasValue($decryptedData, 'nickName', '');
                $weUser->sex = Data::hasValue($decryptedData, 'gender', 0);
                $weUser->city = Data::hasValue($decryptedData, 'city', '');
                $weUser->province = Data::hasValue($decryptedData, 'province', '');
                $weUser->country = Data::hasValue($decryptedData, 'country', '');
                $weUser->avatar = Data::hasValue($decryptedData, 'avatarUrl', '');
                $weUser->weixin_unionid = Data::hasValue($decryptedData, 'unionId', '');
                $weUser->update();

                if (AuthHook::$createUserWhenFirstSubscribe) {
                    \Yii::$app->db->createCommand()->update(
                        User::tableName(),
                        ['userid' => $decryptedData['unionId']],
                        ['id' => $weUser->uid]
                    )->execute();
                }
            }
            HookHelp::on('user_info_response', [$weUser, $weConfig]);
        } catch (\Exception $e) {
            ResponseHelp::returnNo($e->getMessage());
        }

        ResponseHelp::send('success');
    }
}